<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Regular Expression Callouts</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="../css/default.css" rel="stylesheet" type="text/css">
</head>
<body>

<h1>正则表达式全程调用 <span class="ver">[AHK_L 14+]</span></h1>

<p>全程调用提供在正则表达式模式匹配当中临时传递控制到脚本的方法. 关于 PCRE 标准全程调用特性的详细信息, 参见 <a href="http://www.pcre.org/pcre.txt">pcre.txt</a>.</p>

<p>全程调用当前仅由 <a href="../commands/RegExMatch.htm">RegExMatch</a> 和 <a href="../commands/RegExReplace.htm">RegExReplace</a> 支持.</p>

<h3>语法</h3>

<p>在 AutoHotkey_L 中全程调用的语法为 <span class="Syntax">(?C<em>Number</em>:<em>Function</em>)</span>, 此处 <em>Number</em> 和 <em>Function</em> 都是可选的. 只有在指定了 <em>Function</em> 时才需要冒号, 如果省略了 <em>Number</em> 那么冒号是可选的. 如果指定的 <em>Function</em> 不是用户定义的函数名称, 则会出现编译错误并且不会开始模式匹配.</p>

<p>如果省略了 <em>Function</em>, 那么函数名称必须在名为 <b>pcre_callout</b> 的变量中指定. 如果同时存在此名称的全局变量和局部变量, 局部变量优先. 如果 <em>pcre_callout</em> <em></em> 不包含用户定义函数的名称, 那么省略函数的全程调用被忽略.</p>

<h3>全程调用函数</h3>

<pre class="Syntax">Function(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    ...
}</pre>
<p>全程调用函数最多可以定义 5 个参数:</p>
<ul>
  <li><b>Match</b>: 相当于 RegExMatch 函数中的 <em>UnquotedOutputVar</em> 参数, 包含需创建的数组变量.</li>
  <li><b>CalloutNumber</b>: 接收全程调用的 <em>Number</em>.</li>
  <li><b>FoundPos</b>: 接收当前可能匹配的位置.</li>
  <li><b>Haystack</b>: 接收传递到 RegExMatch 或 RegExReplace 函数的 <em>Haystack</em> 参数.</li>
  <li><b>NeedleRegEx</b>: 接收传递到 RegExMatch 或 RegExReplace 函数的 <em>NeedleRegEx</em> 参数.</li>
</ul>
<p>这些名称只是暗示性的. 实际的名称可以改变.</p>

<p>模式匹配可能继续进行或失败, 取决于全程调用函数的返回值:</p>
<ul>
  <li>如果函数返回 <b>0</b> 或不返回一个数值, 匹配操作如常进行.</li>
  <li>如果函数返回 <b>1</b> 或更大的数字, 则在当前位置匹配失败, 但其他匹配的可能性测试继续进行.</li>
  <li>如果函数返回 <b>-1</b>, 匹配中止.</li>
  <li>如果函数返回小于 -1 的值, 它被当成 PCRE 错误码并且匹配中止. RegExMatch 返回空字符串, 而 RegExReplace 返回原始的 <em>Haystack</em>. 在两种情况中, ErrorLevel 包含了错误码.</li>
</ul>

<p>例如:</p>
<pre>Haystack = The quick brown fox jumps over the lazy dog.
RegExMatch(Haystack, "i)(The) (\w+)\b(?CFunc)")
Func(m) {
    MsgBox m=%m%`nm1=%m1%`nm2=%m2%
    return 1
}</pre>
<p>在上面的例子中, 为匹配全程调用之前模式的那部分的每个子字符串调用一次 <em>Func</em>. 使用 <span class="Syntax">\b</span> 排除匹配中不完全的单词例如 <em>The quic</em>, <em>The qui</em>, <em>The qu</em> 等.</p>

<h3 id="EventInfo">EventInfo</h3>

<p>通过 <b>A_EventInfo</b> 可以使用 pcre_callout_block 结构的附加信息.</p>
<pre>version           := NumGet(A_EventInfo,  0, "Int")
callout_number    := NumGet(A_EventInfo,  4, "Int")
offset_vector     := NumGet(A_EventInfo,  8)
subject           := NumGet(A_EventInfo,  8 + A_PtrSize)
subject_length    := NumGet(A_EventInfo,  8 + A_PtrSize*2, "Int")
start_match       := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int")
current_position  := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int")
capture_top       := NumGet(A_EventInfo, 20 + A_PtrSize*2, "Int")
capture_last      := NumGet(A_EventInfo, 24 + A_PtrSize*2, "Int")
pad := A_PtrSize=8 ? 4 : 0  <em>; Compensate for 64-bit data alignment.</em>
callout_data      := NumGet(A_EventInfo, 28 + pad + A_PtrSize*2)
pattern_position  := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int")
next_item_length  := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int")</pre>
<p>更多信息, 参见 <a href="http://www.pcre.org/pcre.txt">pcre.txt</a>, <a href="../Functions.htm#NumGet">NumGet</a> 和 <a href="../Variables.htm#PtrSize">A_PtrSize</a>.</p>

<h3 id="auto">自动全程调用</h3>

<p>在模式选项中包含 <span class="Syntax">C</span> 启用自动全程调用模式. 在此模式中, 在匹配模式的每个项目前插入等于 <span class="Syntax">(?C255)</span> 的全程调用. 例如, 可以使用下面的模板来调试正则表达式:</p>
<pre><em>; Set the default callout function.</em>
pcre_callout = DebugRegEx

<em>; Call RegExMatch with auto-callout option C.</em>
RegExMatch("xxxabc123xyz", "C)abc.*xyz")

DebugRegEx(Match, CalloutNumber, FoundPos, Haystack, NeedleRegEx)
{
    <em>; See pcre.txt for descriptions of these fields.</em>
    start_match       := NumGet(A_EventInfo, 12 + A_PtrSize*2, "Int")
    current_position  := NumGet(A_EventInfo, 16 + A_PtrSize*2, "Int")
    pad := A_PtrSize=8 ? 4 : 0
    pattern_position  := NumGet(A_EventInfo, 28 + pad + A_PtrSize*3, "Int")
    next_item_length  := NumGet(A_EventInfo, 32 + pad + A_PtrSize*3, "Int")

    <em>; Point out &gt;&gt;current match&lt;&lt;.</em>
    _HAYSTACK:=SubStr(Haystack, 1, start_match)
        . "&gt;&gt;" SubStr(Haystack, start_match + 1, current_position - start_match)
        . "&lt;&lt;" SubStr(Haystack, current_position + 1)
    
    <em>; Point out &gt;&gt;next item to be evaluated&lt;&lt;.</em>
    _NEEDLE:=  SubStr(NeedleRegEx, 1, pattern_position)
        . "&gt;&gt;" SubStr(NeedleRegEx, pattern_position + 1, next_item_length)
        . "&lt;&lt;" SubStr(NeedleRegEx, pattern_position + 1 + next_item_length)
    
    ListVars
    <em>; Press Pause to continue.</em>
    Pause
}</pre>

<h3>备注</h3>

<p>全程调用在当前的半线程中执行, 但在全程调用函数返回后将恢复 A_EventInfo 原来的值. 在 RegExMatch 或 RegExReplace 返回时才会设置 ErrorLevel 的值.</p>

</body>
</html>
